/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sdc.net.server.comp;


import java.util.Map;
import java.util.Map.Entry;
import java.util.HashMap;
import sdc.component.type.ComponentType;
import sdc.utility.Pair;
import sdc.utility.EWMAcalculator;
import sdc.event.EventQueue;

/**
 *
 * @author yokoe
 */
public class RequestManager {

	private double capability;

	private double lastUpdateTime;

	private Map<Pair<ComponentType, Double>, Double> arrivalEntries;

        protected Map<ComponentType, Double> ewmaMap;

        private int lostCount;


	public RequestManager(double capability){
		this.capability = capability;
                arrivalEntries = new HashMap<Pair<ComponentType,Double>, Double>();
                ewmaMap = new HashMap<ComponentType, Double>();
                lostCount = 0;
	}

	public double getEwma(ComponentType type){
            if(ewmaMap.containsKey(type)){
		return ewmaMap.get(type);
            }
            else{
                return 0.0;
            }
	}

	public void arrival(ComponentType componentType, double arrivalTime){
		Pair<ComponentType, Double> pair = new Pair<ComponentType, Double>(componentType, arrivalTime);
                if(!ewmaMap.containsKey(componentType)){
                    ewmaMap.put(componentType, 0.0);
                }
                if(arrivalEntries.size() >= 0){
                    arrivalEntries.put(pair, componentType.getWorkload());
                    //System.out.println(arrivalEntries.size());
                }
                else{
                    System.out.println(EventQueue.INSTANCE.getCurrentTime());
                    lostCount++;
                }

		this.updateAllDepartureTime();
	}

	public void departure(ComponentType type, double serviceTime)
	{
                double tmp = EWMAcalculator.calculateCurrentEWMA(serviceTime, ewmaMap.get(type));
                ewmaMap.put(type, tmp);
		this.updateAllDepartureTime();
	}

	private void updateAllDepartureTime()
{
                EventQueue eq = EventQueue.INSTANCE;
		double processedTime = eq.getCurrentTime() - lastUpdateTime;
                Map<Pair<ComponentType,Double>,Double> removeSet = new HashMap<Pair<ComponentType,Double>,Double>();

		for(Entry<Pair<ComponentType, Double>, Double> entry : arrivalEntries.entrySet())
		{
			double remainingProcess = entry.getValue();

			double newRemainingProcess = remainingProcess - ((this.capability / this.arrivalEntries.size()) * processedTime);

                        if(newRemainingProcess <= 0){
                            double serviceTime = eq.getCurrentTime() - entry.getKey().getSecond();
                                //eq.getCurrentTime() - entry.getKey().getSecond() - newRemainingProcess;
                            ComponentType removeType = entry.getKey().getFirst();
                            Pair<ComponentType,Double> pair = new Pair<ComponentType,Double>(removeType,entry.getKey().getSecond());
                            removeSet.put(pair, serviceTime);
                        }
                        else{
                            entry.setValue(newRemainingProcess);
                        }
		}
                for(Entry<Pair<ComponentType,Double>,Double> entry : removeSet.entrySet()){
                    arrivalEntries.remove(entry.getKey());
                    this.departure(entry.getKey().getFirst(), entry.getValue());
                }

		this.lastUpdateTime = eq.getCurrentTime();
	}

}
